// SerialTest.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <windows.h>
#include <stdio.h>

#include <winerror.h>




 void printErrorText( DWORD errorCode) {
		TCHAR buf[512];
		int numChars = ::FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0, errorCode,  0, buf, 512, 0);
		_tprintf(_T("%.*s\n"),numChars, buf);
}

 void listStuff() {
	   TCHAR targetPath[65536];

	 DWORD targetPathLength = QueryDosDevice( NULL, targetPath, sizeof(targetPath) / sizeof(TCHAR));
	 if (targetPathLength == 0) {
		 printErrorText(GetLastError());
		return;
	}

	 DWORD pos = 0;
	 DWORD start = 0;

	 while (pos < targetPathLength) {
		 // print all the 0-delimited strings inside targetPath
		 if (targetPath[pos] == 0) {
			 _tprintf(_T("pos: %u  str: %s\n"), start, (TCHAR*) (targetPath + start));
			start = pos + 1;
		 }
		 ++pos;
	 }
 }

 
 HANDLE openComPort(TCHAR* port) {
	 HANDLE hComm = NULL;
	
	hComm = CreateFile( port,  
						GENERIC_READ | GENERIC_WRITE, 
						0, 
						0, 
						OPEN_EXISTING,	
						0,
						0);
	
	if (hComm == INVALID_HANDLE_VALUE) {
		 printErrorText(GetLastError());
		return hComm;
	}

	// reset the COM port
	FlushFileBuffers(hComm); // try to complete any outstanding operations
	PurgeComm(hComm, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR); // clear any bufferes (deletes all unsent data)

	COMSTAT     comStat;
	DWORD       dwErrorFlags;
	ClearCommError( hComm, &dwErrorFlags, &comStat ); 


	

	/* initialize the COM port */

	// read and modify the port settings
	DCB dcb = {0};
	if (!GetCommState(hComm, &dcb)) {
		printErrorText(GetLastError());
		return hComm;
	}
   

	////RVM
	//dcb.BaudRate = 9600;
	//dcb.fParity = EVENPARITY;
	//dcb.ByteSize = 7;
	//dcb.StopBits = TWOSTOPBITS;
	//// set the correct ASCII Xon/xoff characters
	//dcb.XoffChar = 19;
	//dcb.XonChar = 17;
	//// use Xon/Xoff
	//dcb.fOutX = TRUE;
	//dcb.fInX = TRUE; 

	

	// LED
	dcb.BaudRate = 9600;
	dcb.fParity = EVENPARITY;
	dcb.ByteSize =   7;
	dcb.StopBits = TWOSTOPBITS;
	dcb.fDtrControl = DTR_CONTROL_DISABLE;
	dcb.fOutX = FALSE;
	dcb.fInX = FALSE; 


	// print active settings
	printf("DCBlength : %u\n",dcb.DCBlength);      
	printf("BaudRate : %u\n",dcb.BaudRate);       
	printf("fBinary : %u\n",dcb.fBinary);     
	printf("fParity : %u\n",dcb.fParity);     
	printf("fOutxCtsFlow : %u\n",dcb.fOutxCtsFlow); 
	printf("fOutxDsrFlow : %u\n",dcb.fOutxDsrFlow); 
	printf("fDtrControl : %u\n",dcb.fDtrControl);  
	printf("fDsrSensitivity : %u\n",dcb.fDsrSensitivity); 
	printf("fTXContinueOnXoff : %u\n",dcb.fTXContinueOnXoff); 
	printf("fOutX : %u\n",dcb.fOutX);       
	printf("fInX : %u\n",dcb.fInX);        
	printf("fErrorChar : %u\n",dcb.fErrorChar);  
	printf("fNull : %u\n",dcb.fNull);       
	printf("fRtsControl : %u\n",dcb.fRtsControl);  
	printf("fAbortOnError : %u\n",dcb.fAbortOnError); 
	printf("fDummy2 : %u\n",dcb.fDummy2);     
	printf("wReserved : %u\n",dcb.wReserved);       
	printf("XonLim : %u\n",dcb.XonLim);          
	printf("XoffLim : %u\n",dcb.XoffLim);         
	printf("ByteSize : %u\n",dcb.ByteSize);        
	printf("Parity : %u\n",dcb.Parity);          
	printf("StopBits : %u\n",dcb.StopBits);        
	printf("XonChar : %u\n",dcb.XonChar);         
	printf("XoffChar : %u\n",dcb.XoffChar);        
	printf("ErrorChar : %u\n",dcb.ErrorChar);       
	printf("EofChar : %u\n",dcb.EofChar);         
	printf("EvtChar : %u\n",dcb.EvtChar);         
	printf("wReserved1 : %u\n",dcb.wReserved1);   


	// Set the altered Com port settings
	if (!SetCommState(hComm, &dcb)) {
		 printErrorText(GetLastError());
		return hComm;
	}


	// Set the timeout settings for the port
	// The timeouts define when a read operation is completed and ReadFile() returns
	COMMTIMEOUTS commtimeouts = {0};
	if (!GetCommTimeouts(hComm, &commtimeouts)) {
		 printErrorText(GetLastError());
		return hComm;
	}
	
	/*
	If an application sets ReadIntervalTimeout and ReadTotalTimeoutMultiplier to MAXDWORD and sets ReadTotalTimeoutConstant to a value greater than zero and less than MAXDWORD, one of the following occurs when the ReadFile function is called:
	If there are any bytes in the input buffer, ReadFile returns immediately with the bytes in the buffer.
	If there are no bytes in the input buffer, ReadFile waits until a byte arrives and then returns immediately.
	If no bytes arrive within the time specified by ReadTotalTimeoutConstant, ReadFile times out.
	*/

	commtimeouts.ReadIntervalTimeout = MAXDWORD;
	commtimeouts.ReadTotalTimeoutMultiplier = MAXDWORD;
	commtimeouts.ReadTotalTimeoutConstant = MAXDWORD - 1; // return only when data was received (technically after MAXDWORD-1 ms)

	if (!SetCommTimeouts(hComm, &commtimeouts)) {
		 printErrorText(GetLastError());
		 return hComm;
	}

	return hComm;
 }
 

 void readStuff(HANDLE hComm) {

	unsigned char buf[128] = {0};
	DWORD bytesRead = 0;

	bytesRead = 0;

	ZeroMemory(buf,sizeof(buf));

	if (ReadFile( hComm, buf, sizeof(buf), &bytesRead, NULL)) 
	{
		//printf( "%.*s", bytesRead, buf);
		printf( "%c%c%c%c%c%c%c%c %c %u\n",
			((buf[0]>>7)&1) +48,
			((buf[0]>>6)&1) +48,
			((buf[0]>>5)&1) +48,
			((buf[0]>>4)&1) +48,
			((buf[0]>>3)&1) +48,
			((buf[0]>>2)&1) +48,
			((buf[0]>>1)&1) +48,
			((buf[0]>>0)&1) +48,
			buf[0],
			buf[0]
		);

	} 
	else 
	{
		DWORD lastError = GetLastError();
		printErrorText(lastError);
	}

 }



 void writeStuff(HANDLE hComm, const char* text, size_t bufsize) {
	DWORD bytesWritten;
	WriteFile(	hComm, 
				text, 
				bufsize,  // don't send the string terminator
				&bytesWritten, 
				NULL);
 }



int _tmain(int argc, _TCHAR* argv[])
{
	HANDLE hComm = openComPort(_T("COM4"));

	const char msg[] = "r";
	while(true) {
		Sleep(1000);
		writeStuff(hComm, msg, sizeof(msg)-1);
		readStuff(hComm);
	}
	//readStuff(hComm);
	CloseHandle(hComm);
	return 0;
}

